package com.luke.exercise.concurrent;

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    
    public static void main(String[] args) {
        String[] names = {"aa","bb","cc","dd","ee"};
        for(int i=0, len = names.length;i<len; i++) {
            new Thread(new Philosopher(i, names[i])).start();
        }
    }
}

class AppContext {
    public static final int NUM_FORKS = 5;
    public static final int NUM_PHILO = 5;
    
    public static Semaphore[] forks;
    public static Semaphore counter;
    
    static {
        forks = new Semaphore[NUM_FORKS];
        
        for(int i=0,len= forks.length;i<len;i++) {
            forks[i] = new Semaphore(1);
        }
        
        counter = new Semaphore(NUM_PHILO-1);
    }
    
    public static void putOnFork(int index, boolean leftFitst) throws InterruptedException {
        if(leftFitst) {
            forks[index].acquire();
            forks[(index+1)%NUM_PHILO].acquire();
        } else {
            forks[(index + 1) % NUM_PHILO].acquire();
            forks[index].acquire();
        }
    }
    
    public static void putDownFork(int index, boolean leftFirst) {
        if(leftFirst) {
            forks[index].release();
            forks[(index + 1) % NUM_FORKS].release();
        } else {
            forks[(index + 1) % NUM_FORKS].release();
            forks[index].release();
        }
    }
}

class Philosopher implements Runnable {

    private int index;
    
    private String name;
    
    public Philosopher(int index, String name) {
        this.index = index;
        this.name = name;
    }
    
    public void run() {
        while(true) {
            try {
                AppContext.counter.acquire();
                boolean leftFirst = index % 2 == 0 ;
                AppContext.putOnFork(index, leftFirst);
                System.out.println(name + "正在吃面");
                AppContext.putDownFork(index, leftFirst);
                AppContext.counter.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }
    
}